#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include <sys/sem.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/mman.h>

#define FILENAME "/tmp/out"
#define BUFSIZE  64
#define COUNT    20

static int semid;

static void P(void) // 取信号
{
	struct sembuf sop;
 
	sop.sem_num = 0; // 数组下标
	sop.sem_op = -1; // 取一个
	sop.sem_flg = 0; // 无特殊要求

	if (-1 == semop(semid, &sop, 1)) {
		perror("Error getting sem");
		return;
	}
}

static void V(void) // 还信号
{
	struct sembuf sop;
 
	sop.sem_num = 0; // 数组下标
	sop.sem_op =  1; // 放一个
	sop.sem_flg = 0; // 无特殊要求

	if (-1 == semop(semid, &sop, 1)) {
		perror("Error getting sem");
		return;
	}
}

static void rw_file(void)
{
	FILE *fp = NULL;
	char buf[BUFSIZE] = {0};
	int num;

	fp = fopen(FILENAME, "r+");
	if (NULL == fp) {
		perror("Error opening file");
		return;
	}

	P(); // 取信号
	fgets(buf, BUFSIZE, fp);
	num = atoi(buf) + 1;

	//fseek(fp, 0, SEEK_SET); // 回溯到开头
	rewind(fp);
	fprintf(fp, "%d", num);

	printf("[%d] Update number to: <%d>\n", getpid(), num);

	fclose(fp);

	V(); // 还信号
}

int main(void)
{
	pid_t pid;
	int i;
	FILE *fp;

	semid = semget(IPC_PRIVATE, 1, IPC_CREAT | IPC_EXCL | 0600);
	if (-1 == semid) {
		perror("Error getting sem");
		exit(1);
	}

	semctl(semid, 0, SETVAL, 1);

	fp = fopen(FILENAME, "w");
	if (NULL == fp) {
		perror("Error opening file");
		exit(1);
	}
	fputs("0", fp);
	fclose(fp);
	
	for (i = 0; i < COUNT; i++) {
		pid = fork();
		if (-1 == pid) {
			perror("Error forking process");
			exit(1);
		}
		if (0 == pid) {
			rw_file();
			exit(0);
		}
	}

	for (i = 0; i < COUNT; i++) {
		wait(NULL);
	}

	semctl(semid, 0, IPC_RMID, NULL);

	exit(0);
}
